﻿using System;
using System.Runtime.InteropServices;

namespace __Able.Core.Utilities
{
    /*
        private struct Modes
        {
            public int UserID;
            public int UserHeap;
        }
    
            int totalNum = 10000 * 10000;
            using (CompactHeap<Modes> heap = new CompactHeap<Modes>(totalNum))
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                for (int i = 0; i < totalNum; i++)
                {
                    Modes m = new Modes();
                    m.UserID = i;
                    m.UserHeap = i;
                    heap.Add(m);
                }
                sw.Stop();
                Console.WriteLine("add:" + sw.ElapsedMilliseconds + "ms");

                Modes m500000 = heap.Get(500000);
                Console.WriteLine("m500000:" + m500000.UserID);

                Modes m8 = heap.Get(8);
                Console.WriteLine("m8:" + m8.UserID);
            }
            Console.Read();
     * 
     */
    /// <summary>
    /// 注意：CompactHeap的T必须为struct类型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CompactHeap<T> : IDisposable where T : new()
    {
        #region Fields

        private IntPtr _ptr, _currPtr;
        private int _rawSize;
        private Type _type;
        private T _t;

        #endregion

        public CompactHeap(int num)
        {
            _t = new T();
            _type = _t.GetType();

            _rawSize = Marshal.SizeOf(_t);
            _ptr = Marshal.AllocHGlobal(_rawSize * num);
            _currPtr = _ptr;
        }

        public void Add(T t)
        {
            Marshal.StructureToPtr(t, _ptr, false);
            _ptr = new IntPtr((_ptr.ToInt32() + _rawSize));
        }

        public T Get(int index)
        {
            IntPtr p = new IntPtr((_currPtr.ToInt32() + _rawSize * index));
            return (T)Marshal.PtrToStructure(p, _type);
        }

        public void Dispose()
        {
            Marshal.FreeHGlobal(_currPtr);
        }
    }
}
